package com.wxtech.heartbeat.database;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.sql.SQLException;
import java.util.Collection;

import javax.naming.InitialContext;
import javax.sql.DataSource;

import org.apache.log4j.Logger;

import com.wxtech.heartbeat.Config;
import com.wxtech.heartbeat.model.DataCollect;
import com.wxtech.heartbeat.model.Device;
import com.wxtech.heartbeat.model.ErrorData;
import com.wxtech.heartbeat.model.HeartBeat;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;



public class DataManager {
    
    private static Logger logger = Logger.getLogger(DataManager.class);
    private final Config config;
    private DataSource dataSource;
    
    public DataManager(Config config) throws Exception {
        this.config = config;
        
        initDatabase();
    }
    
    public DataSource getDataSource() {
        return dataSource;
    }
    
    private void initDatabase() throws Exception {
        
        String jndiName = config.getString("database.jndi");
        
        if (jndiName != null) {
            
            dataSource = (DataSource) new InitialContext().lookup(jndiName);
            
        } else {
            
            String driverFile = config.getString("database.driverFile");
            if (driverFile != null) {
                URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
                Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
                method.setAccessible(true);
                method.invoke(classLoader, new File(driverFile).toURI().toURL());
            }
            
            String driver = config.getString("database.driver");
            if (driver != null) {
                Class.forName(driver);
            }
            
            HikariConfig hikariConfig = new HikariConfig();
            hikariConfig.setDriverClassName(config.getString("database.driver"));
            hikariConfig.setJdbcUrl(config.getString("database.url"));
            hikariConfig.setUsername(config.getString("database.user"));
            hikariConfig.setPassword(config.getString("database.password"));
            hikariConfig.setConnectionInitSql(config.getString("database.checkConnection", "SELECT 1"));
            hikariConfig.setIdleTimeout(600000);
            
            int maxPoolSize = config.getInteger("database.maxPoolSize");
            
            if (maxPoolSize != 0) {
                hikariConfig.setMaximumPoolSize(maxPoolSize);
            }
            
            dataSource = new HikariDataSource(hikariConfig);
            
        }
    }
    
    private String getQuery(String key) {
        String query = config.getString(key);
        if (query == null) {
            logger.info("Query not provided: " + key);
        } else {
            logger.debug(query);
        }
        return query;
    }
    
    public void addErrorData(ErrorData errorData) throws SQLException {
        errorData.setId(QueryBuilder.create(dataSource, getQuery("database.insertErrorData"), true)
                        .setObject(errorData)
                        .executeUpdate());
    }
    
    public Collection<Device> getDeviceAll() throws SQLException {
        return QueryBuilder.create(dataSource, getQuery("database.selectDeviceAll")).executeQuery(Device.class);
    }
    
    public void addDevice(Device device) throws SQLException {
        device.setId(QueryBuilder.create(dataSource, getQuery("database.insertDevice"), true)
                     .setString("device_id", device.getDevice_id())
                     .executeUpdate());
    }
    
    public void addHeartBeat(HeartBeat hb) throws SQLException {
        hb.setId(QueryBuilder.create(dataSource, getQuery("database.insertHeartBeat"), true)
                 .setString("deviceId", hb.getDeviceId())
                 .setDate("dateTime", hb.getDateTime())
                 .setString("serial", hb.getSerial())
                 .setString("simId", hb.getSimId())
                 .executeUpdate());
    }
    
    
    public void addDataCollect(DataCollect dc) throws SQLException {
        dc.setId(QueryBuilder.create(dataSource, getQuery("database.insertDataCollect"), true)
                 .setString("deviceId", dc.getDeviceId())
                 .setDate("dateTime", dc.getDateTime())
                 .setFloat("cumulativeGongAmount", dc.getCumulativeGongAmount())
                 .setFloat("cumulativeBiaoAmount", dc.getCumulativeBiaoAmount())
                 .setFloat("temperture", dc.getTemperture())
                 .setFloat("pressure", dc.getPressure())
                 .setShort("interFwdChannelSNR", dc.getInterFwdChannelSNR())
                 .setShort("interRvsChannelSNR", dc.getInterRvsChannelSNR())
                 .setShort("upFwdChannelSNR", dc.getUpFwdChannelSNR())
                 .setShort("upRvsChannelSNR", dc.getUpRvsChannelSNR())
                 .setShort("lowFwdChannelSNR", dc.getLowFwdChannelSNR())
                 .setShort("lowRvsChannelSNR", dc.getLowRvsChannelSNR())
                 .setShort("interFwdChannelGain", dc.getInterFwdChannelGain())
                 .setShort("interRvsChannelGain", dc.getInterRvsChannelGain())
                 .setShort("upFwdChannelGain", dc.getUpFwdChannelGain())
                 .setShort("upRvsChannelGain", dc.getUpRvsChannelGain())
                 .setShort("lowFwdChannelGain", dc.getLowFwdChannelGain())
                 .setShort("lowRvsChannelGain", dc.getLowRvsChannelGain())
                 .setFloat("upChannelSoundVelocity", dc.getUpChannelSoundVelocity())
                 .setFloat("interChannelSoundVelocity", dc.getInterChannelSoundVelocity())
                 .setFloat("lowChannelSoundVelocity", dc.getLowChannelSoundVelocity())
                 .setFloat("upChannelFlowVelocity", dc.getUpChannelFlowVelocity())
                 .setFloat("interChannelFlowVelocity", dc.getInterChannelFlowVelocity())
                 .setFloat("lowChannelFlowVelocity", dc.getLowChannelFlowVelocity())
                 .setFloat("currentFlow", dc.getCurrentFlow())
                 .setString("batteryStatus", dc.getBatteryStatus() + "%")
                 .executeUpdate());
    }
    
    public Device getDevice(String device_id) throws SQLException {
        return QueryBuilder.create(dataSource, getQuery("database.selectDevice"))
        .setString("device_id", device_id)
        .executeQuerySingle(Device.class);
    }
    
    public void deleteDevice(String deviceId) throws SQLException {
        QueryBuilder.create(dataSource, getQuery("database.deleteDevice"), true)
        .setString("device_id", deviceId)
        .executeUpdate();
    }
    
    public void deleteHeartBeat(String deviceId) throws SQLException {
        QueryBuilder.create(dataSource, getQuery("database.deleteHeartBeat"), true)
        .setString("device_id", deviceId)
        .executeUpdate();
    }
    
    public void deleteDataCollect(String deviceId) throws SQLException {
        QueryBuilder.create(dataSource, getQuery("database.deleteDataCollect"), true)
        .setString("device_id", deviceId)
        .executeUpdate();
    }
    
    public void deleteErrorData(int errorCode) throws SQLException {
        QueryBuilder.create(dataSource, getQuery("database.deleteErrorData"), true)
        .setInteger("error_code", errorCode)
        .executeUpdate();
    }
    
    
    public String getRedisIp() {
        return config.getString("redis_ip");
    }

    public String getRedisPort() {
        return config.getString("redis_port");
    }

    // database.updatePendingParamConfigCmd
    /*
     public User login(String email, String password) throws SQLException {
     User user = QueryBuilder.create(dataSource, getQuery("database.loginUser"))
     .setString("email", email)
     .executeQuerySingle(User.class);
     if (user != null && user.isPasswordValid(password)) {
     return user;
     } else {
     return null;
     }
     }
     
     public Collection<User> getUsers() throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectUsersAll"))
     .executeQuery(User.class);
     }
     
     public void addUser(User user) throws SQLException {
     user.setId(QueryBuilder.create(dataSource, getQuery("database.insertUser"), true)
     .setObject(user)
     .executeUpdate());
     }
     
     public void updateUser(User user) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.updateUser"))
     .setObject(user)
     .executeUpdate();
     if (user.getHashedPassword() != null) {
     QueryBuilder.create(dataSource, getQuery("database.updateUserPassword"))
     .setObject(user)
     .executeUpdate();
     }
     }
     
     public void removeUser(long userId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.deleteUser"))
     .setLong("id", userId)
     .executeUpdate();
     }
     
     public Collection<DevicePermission> getDevicePermissions() throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectDevicePermissions"))
     .executeQuery(DevicePermission.class);
     }
     
     public Collection<GroupPermission> getGroupPermissions() throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectGroupPermissions"))
     .executeQuery(GroupPermission.class);
     }
     
     public Collection<Device> getAllDevices() throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectDevicesAll"))
     .executeQuery(Device.class);
     }
     
     public void addDevice(Device device) throws SQLException {
     device.setId(QueryBuilder.create(dataSource, getQuery("database.insertDevice"), true)
     .setObject(device)
     .executeUpdate());
     }
     
     public void updateDevice(Device device) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.updateDevice"))
     .setObject(device)
     .executeUpdate();
     }
     
     public void updateDeviceStatus(Device device) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.updateDeviceStatus"))
     .setObject(device)
     .executeUpdate();
     }
     
     public void removeDevice(long deviceId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.deleteDevice"))
     .setLong("id", deviceId)
     .executeUpdate();
     }
     
     public void linkDevice(long userId, long deviceId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.linkDevice"))
     .setLong("userId", userId)
     .setLong("deviceId", deviceId)
     .executeUpdate();
     }
     
     public void unlinkDevice(long userId, long deviceId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.unlinkDevice"))
     .setLong("userId", userId)
     .setLong("deviceId", deviceId)
     .executeUpdate();
     }
     
     public Collection<Group> getAllGroups() throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectGroupsAll"))
     .executeQuery(Group.class);
     }
     
     public void addGroup(Group group) throws SQLException {
     group.setId(QueryBuilder.create(dataSource, getQuery("database.insertGroup"), true)
     .setObject(group)
     .executeUpdate());
     }
     
     public void updateGroup(Group group) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.updateGroup"))
     .setObject(group)
     .executeUpdate();
     }
     
     public void removeGroup(long groupId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.deleteGroup"))
     .setLong("id", groupId)
     .executeUpdate();
     }
     
     public void linkGroup(long userId, long groupId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.linkGroup"))
     .setLong("userId", userId)
     .setLong("groupId", groupId)
     .executeUpdate();
     }
     
     public void unlinkGroup(long userId, long groupId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.unlinkGroup"))
     .setLong("userId", userId)
     .setLong("groupId", groupId)
     .executeUpdate();
     }
     
     public Collection<Position> getPositions(long deviceId, Date from, Date to) throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectPositions"))
     .setLong("deviceId", deviceId)
     .setDate("from", from)
     .setDate("to", to)
     .executeQuery(Position.class);
     }
     
     public Position getPosition(long positionId) throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectPosition"))
     .setLong("id", positionId)
     .executeQuerySingle(Position.class);
     }
     
     public void addPosition(Position position) throws SQLException {
     position.setId(QueryBuilder.create(dataSource, getQuery("database.insertPosition"), true)
     .setDate("now", new Date())
     .setObject(position)
     .executeUpdate());
     }
     
     public void updateLatestPosition(Position position) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.updateLatestPosition"))
     .setDate("now", new Date())
     .setObject(position)
     .executeUpdate();
     }
     
     public Collection<Position> getLatestPositions() throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectLatestPositions"))
     .executeQuery(Position.class);
     }
     
     public void clearHistory() throws SQLException {
     long historyDays = config.getInteger("database.historyDays");
     if (historyDays != 0) {
     Date timeLimit = new Date(System.currentTimeMillis() - historyDays * 24 * 3600 * 1000);
     QueryBuilder.create(dataSource, getQuery("database.deletePositions"))
     .setDate("serverTime", timeLimit)
     .executeUpdate();
     QueryBuilder.create(dataSource, getQuery("database.deleteEvents"))
     .setDate("serverTime", timeLimit)
     .executeUpdate();
     }
     }
     
     public Server getServer() throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectServers"))
     .executeQuerySingle(Server.class);
     }
     
     public void updateServer(Server server) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.updateServer"))
     .setObject(server)
     .executeUpdate();
     }
     
     public Event getEvent(long eventId) throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectEvent"))
     .setLong("id", eventId)
     .executeQuerySingle(Event.class);
     }
     
     public void addEvent(Event event) throws SQLException {
     event.setId(QueryBuilder.create(dataSource, getQuery("database.insertEvent"), true)
     .setObject(event)
     .executeUpdate());
     }
     
     public Collection<Event> getEvents(long deviceId, Date from, Date to) throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectEvents"))
     .setLong("deviceId", deviceId)
     .setDate("from", from)
     .setDate("to", to)
     .executeQuery(Event.class);
     }
     
     public Collection<Geofence> getGeofences() throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectGeofencesAll"))
     .executeQuery(Geofence.class);
     }
     
     public void addGeofence(Geofence geofence) throws SQLException {
     geofence.setId(QueryBuilder.create(dataSource, getQuery("database.insertGeofence"), true)
     .setObject(geofence)
     .executeUpdate());
     }
     
     public void updateGeofence(Geofence geofence) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.updateGeofence"))
     .setObject(geofence)
     .executeUpdate();
     }
     
     public void removeGeofence(long geofenceId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.deleteGeofence"))
     .setLong("id", geofenceId)
     .executeUpdate();
     }
     
     public Collection<GeofencePermission> getGeofencePermissions() throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectGeofencePermissions"))
     .executeQuery(GeofencePermission.class);
     }
     
     public void linkGeofence(long userId, long geofenceId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.linkGeofence"))
     .setLong("userId", userId)
     .setLong("geofenceId", geofenceId)
     .executeUpdate();
     }
     
     public void unlinkGeofence(long userId, long geofenceId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.unlinkGeofence"))
     .setLong("userId", userId)
     .setLong("geofenceId", geofenceId)
     .executeUpdate();
     }
     
     public Collection<GroupGeofence> getGroupGeofences() throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectGroupGeofences"))
     .executeQuery(GroupGeofence.class);
     }
     
     public void linkGroupGeofence(long groupId, long geofenceId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.linkGroupGeofence"))
     .setLong("groupId", groupId)
     .setLong("geofenceId", geofenceId)
     .executeUpdate();
     }
     
     public void unlinkGroupGeofence(long groupId, long geofenceId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.unlinkGroupGeofence"))
     .setLong("groupId", groupId)
     .setLong("geofenceId", geofenceId)
     .executeUpdate();
     }
     
     public Collection<DeviceGeofence> getDeviceGeofences() throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectDeviceGeofences"))
     .executeQuery(DeviceGeofence.class);
     }
     
     public void linkDeviceGeofence(long deviceId, long geofenceId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.linkDeviceGeofence"))
     .setLong("deviceId", deviceId)
     .setLong("geofenceId", geofenceId)
     .executeUpdate();
     }
     
     public void unlinkDeviceGeofence(long deviceId, long geofenceId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.unlinkDeviceGeofence"))
     .setLong("deviceId", deviceId)
     .setLong("geofenceId", geofenceId)
     .executeUpdate();
     }
     
     public Collection<Notification> getNotifications() throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectNotifications"))
     .executeQuery(Notification.class);
     }
     
     public void addNotification(Notification notification) throws SQLException {
     notification.setId(QueryBuilder.create(dataSource, getQuery("database.insertNotification"), true)
     .setObject(notification)
     .executeUpdate());
     }
     
     public void updateNotification(Notification notification) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.updateNotification"))
     .setObject(notification)
     .executeUpdate();
     }
     
     public void removeNotification(Notification notification) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.deleteNotification"))
     .setLong("id", notification.getId())
     .executeUpdate();
     }
     
     public Collection<AttributeAlias> getAttributeAliases() throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectAttributeAliases"))
     .executeQuery(AttributeAlias.class);
     }
     
     public void addAttributeAlias(AttributeAlias attributeAlias) throws SQLException {
     attributeAlias.setId(QueryBuilder.create(dataSource, getQuery("database.insertAttributeAlias"), true)
     .setObject(attributeAlias)
     .executeUpdate());
     }
     
     public void updateAttributeAlias(AttributeAlias attributeAlias) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.updateAttributeAlias"))
     .setObject(attributeAlias)
     .executeUpdate();
     }
     
     public void removeAttributeAlias(long attributeAliasId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.deleteAttributeAlias"))
     .setLong("id", attributeAliasId)
     .executeUpdate();
     }
     
     public Collection<Statistics> getStatistics(Date from, Date to) throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectStatistics"))
     .setDate("from", from)
     .setDate("to", to)
     .executeQuery(Statistics.class);
     }
     
     public void addStatistics(Statistics statistics) throws SQLException {
     statistics.setId(QueryBuilder.create(dataSource, getQuery("database.insertStatistics"), true)
     .setObject(statistics)
     .executeUpdate());
     }
     
     public Collection<Calendar> getCalendars() throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectCalendarsAll"))
     .executeQuery(Calendar.class);
     }
     
     public void addCalendar(Calendar calendar) throws SQLException {
     calendar.setId(QueryBuilder.create(dataSource, getQuery("database.insertCalendar"), true)
     .setObject(calendar)
     .executeUpdate());
     }
     
     public void updateCalendar(Calendar calendar) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.updateCalendar"))
     .setObject(calendar)
     .executeUpdate();
     }
     
     public void removeCalendar(long calendarId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.deleteCalendar"))
     .setLong("id", calendarId)
     .executeUpdate();
     }
     
     public Collection<CalendarPermission> getCalendarPermissions() throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectCalendarPermissions"))
     .executeQuery(CalendarPermission.class);
     }
     
     public void linkCalendar(long userId, long calendarId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.linkCalendar"))
     .setLong("userId", userId)
     .setLong("calendarId", calendarId)
     .executeUpdate();
     }
     
     public void unlinkCalendar(long userId, long calendarId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.unlinkCalendar"))
     .setLong("userId", userId)
     .setLong("calendarId", calendarId)
     .executeUpdate();
     }
     
     public Collection<UserPermission> getUserPermissions() throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectUserPermissions"))
     .executeQuery(UserPermission.class);
     }
     
     public void linkUser(long userId, long managedUserId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.linkUser"))
     .setLong("userId", userId)
     .setLong("managedUserId", managedUserId)
     .executeUpdate();
     }
     
     public void unlinkUser(long userId, long managedUserId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.unlinkUser"))
     .setLong("userId", userId)
     .setLong("managedUserId", managedUserId)
     .executeUpdate();
     }
     
     public Collection<Attribute> getAttributes() throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectAttributes"))
     .executeQuery(Attribute.class);
     }
     
     public void addAttribute(Attribute attribute) throws SQLException {
     attribute.setId(QueryBuilder.create(dataSource, getQuery("database.insertAttribute"), true)
     .setObject(attribute)
     .executeUpdate());
     }
     
     public void updateAttribute(Attribute attribute) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.updateAttribute"))
     .setObject(attribute)
     .executeUpdate();
     }
     
     public void removeAttribute(long computedAttributeId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.deleteAttribute"))
     .setLong("id", computedAttributeId)
     .executeUpdate();
     }
     
     public Collection<AttributePermission> getAttributePermissions() throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectAttributePermissions"))
     .executeQuery(AttributePermission.class);
     }
     
     public void linkAttribute(long userId, long attributeId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.linkAttribute"))
     .setLong("userId", userId)
     .setLong("attributeId", attributeId)
     .executeUpdate();
     }
     
     public void unlinkAttribute(long userId, long attributeId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.unlinkAttribute"))
     .setLong("userId", userId)
     .setLong("attributeId", attributeId)
     .executeUpdate();
     }
     
     public Collection<GroupAttribute> getGroupAttributes() throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectGroupAttributes"))
     .executeQuery(GroupAttribute.class);
     }
     
     public void linkGroupAttribute(long groupId, long attributeId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.linkGroupAttribute"))
     .setLong("groupId", groupId)
     .setLong("attributeId", attributeId)
     .executeUpdate();
     }
     
     public void unlinkGroupAttribute(long groupId, long attributeId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.unlinkGroupAttribute"))
     .setLong("groupId", groupId)
     .setLong("attributeId", attributeId)
     .executeUpdate();
     }
     
     public Collection<DeviceAttribute> getDeviceAttributes() throws SQLException {
     return QueryBuilder.create(dataSource, getQuery("database.selectDeviceAttributes"))
     .executeQuery(DeviceAttribute.class);
     }
     
     public void linkDeviceAttribute(long deviceId, long attributeId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.linkDeviceAttribute"))
     .setLong("deviceId", deviceId)
     .setLong("attributeId", attributeId)
     .executeUpdate();
     }
     
     public void unlinkDeviceAttribute(long deviceId, long attributeId) throws SQLException {
     QueryBuilder.create(dataSource, getQuery("database.unlinkDeviceAttribute"))
     .setLong("deviceId", deviceId)
     .setLong("attributeId", attributeId)
     .executeUpdate();
     }
     */
    
}
